package ru.spb.osll.myfit.client;

import ru.spb.osll.myfit.client.log.RemoteLogger;
import ru.spb.osll.myfit.client.manager.PageElementManager;
import ru.spb.osll.myfit.client.manager.PageExecutingManager;
import ru.spb.osll.myfit.client.service.FitService;
import ru.spb.osll.myfit.client.service.FitServiceAsync;
import ru.spb.osll.myfit.client.widget.GWTWidgetFactory;
import ru.spb.osll.myfit.client.widget.PageWidget;
import ru.spb.osll.myfit.common.Page;
import ru.spb.osll.myfit.common.PageElement;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.VerticalPanel;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class Fitnesse implements EntryPoint {

  /**
   * The message displayed to the user when the server cannot be reached or
   * returns an error.
   */
  private static final String SERVER_ERROR = "An error occurred while "
      + "attempting to contact the server. Please check your network " + 
      "connection and try again.";

  private MyFitView m_view;

  /**
   * Tests path
   */
  private String m_testPath = "";

  private DialogBox m_errorDialog;

  /**
   * Create a remote service proxy to talk to the server-side Fit service.
   */
  private final FitServiceAsync m_fitService = GWT.create(FitService.class);

  private void createErrorDialog() {
    m_errorDialog = new DialogBox();
    m_errorDialog.setText("Remote Procedure Call");
    m_errorDialog.setAnimationEnabled(true);
    final Button closeButton = new Button("Close");
    closeButton.getElement().setId("closeButton");
    final HTML serverResponseLabel = new HTML();
    VerticalPanel dialogVPanel = new VerticalPanel();
    dialogVPanel.addStyleName("dialogVPanel");
    dialogVPanel.setHorizontalAlignment(VerticalPanel.ALIGN_RIGHT);
    dialogVPanel.add(closeButton);
    dialogVPanel.add(serverResponseLabel);
    m_errorDialog.setWidget(dialogVPanel);
    m_errorDialog.setText("Remote Procedure Call - Failure");
    serverResponseLabel.addStyleName("serverResponseLabelError");
    serverResponseLabel.setHTML(SERVER_ERROR);

    closeButton.addClickHandler(new ClickHandler() {
      public void onClick(ClickEvent event) {
        m_errorDialog.hide();
      }
    });
  }

  public void savePage(String path, Page page) {
    m_fitService.savePage(path, page, new AsyncCallback<Object>() {
      public void onFailure(final Throwable caught) {
        m_errorDialog.setText(caught.getMessage());
        m_errorDialog.center();
      }

      public void onSuccess(final Object result) {
      }
    });
  }

  public void onModuleLoad() {

    createErrorDialog();
    PageWidget pageWidget = new PageWidget(new GWTWidgetFactory());
    PageElementManager pageElementManager = new PageElementManager();
    pageElementManager.addErrorDialog(m_errorDialog);
    pageWidget.addPageEventListener(pageElementManager);
    PageExecutingManager m_pageExecutingManager = new PageExecutingManager();

    setPagePathAndLoad();
    m_view = new MyFitView(getPath(), pageWidget, m_pageExecutingManager, this);
    RootPanel.get().add(m_view.getRootWidget());
  }

  private void loadStartPage() {
    m_fitService.loadPage(getPath(), new AsyncCallback<Page>() {

      public void onFailure(Throwable caught) {
        m_errorDialog.center();
      }

      public void onSuccess(Page page) {
        String path = getPath();
        m_view.clear();
        m_view.setPagePath(path);
        handlePage(page);
      }
    });
  }

  private String getPath() {
    if (m_testPath != null && !m_testPath.isEmpty()) {
      RemoteLogger.log(2, "client getPath() = " + m_testPath);
      return m_testPath;
    } else {
      RemoteLogger.log(2, "client getPath() = " + "");
      return "";
    }
  }

  /**
   * Get screen width
   * 
   * @return screen width
   */
  native public static int getScreenWidth()/*-{
                                           return $wnd.screen.width;
                                           }-*/;

  /**
   * Set page path from address bar.
   */
  private void setPagePathAndLoad() {
    m_fitService.getPagePath(new AsyncCallback<String>() {

      @Override
      public void onFailure(Throwable caught) {
        caught.printStackTrace();
        m_errorDialog.center();
      }

      @Override
      public void onSuccess(String result) {
        m_testPath = result;
        loadStartPage();
      }
    });
  }

  /**
   * handles loaded page
   * 
   * @param page
   *          - loaded page
   */
  private void handlePage(Page page) {
    if (page != null) {
      for (PageElement element : page.getElements()) {
        m_view.addPageElementWidget(element);
      }
    }
  }
}